package com.gitee.huanminabc.utils_tools.config_refresh.core;

import com.gitee.huanminabc.utils_tools.config_refresh.utils.SpELUtil;
import com.gitee.huanminabc.utils_tools.spring_base.utils.SpringAopProxyUtil;
import com.gitee.huanminabc.utils_tools.spring_base.utils.SpringContextUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class ConfigRefreshProcessor implements BeanPostProcessor {
    private Map<String, Object> map = new HashMap<>(); //保留需要进行配置刷新的bean

    //在bean初始化之前执行
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    //在bean初始化之后执行
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("requestController")){
            System.out.println("beanName = " + beanName);
        }
        //获取bean的目标类型,因为有些对象是代理对象
        Class targetClass = SpringAopProxyUtil.getTargetClass(bean);

        findValue(targetClass,bean, beanName);
        return bean;
    }

    //查找所有的bean里面成员变量中使用了@Value注解的变量
    //如果使用了@Value注解，就将这个bean放入map中
    //这样就可以在配置刷新的时候，找到所有需要刷新的bean
    private void findValue(Class classTarget,Object bean, String beanName) {
        //获取bean的所有成员变量
        Field[] fields = classTarget.getDeclaredFields();
        for (Field field : fields) {
            //判断成员变量是否使用了@Value注解
            Value value = field.getAnnotation(Value.class);
            if (value != null) {
                //将bean放入map中
                map.put(beanName, bean);
                break;
            }
        }
    }



    //获取满足@Value(“${xxx}”)的bean
    public List<Object> getBeans(String key) {
        List<Object> list = new ArrayList<>();
        for (Map.Entry<String, Object> stringObjectEntry : map.entrySet()) {
            Object value = stringObjectEntry.getValue();
            //获取bean的目标类型,因为有些对象是代理对象
            Class targetClass = SpringAopProxyUtil.getTargetClass(value);
            Field[] fields = targetClass.getDeclaredFields();
            for (Field field : fields) {
                Value value1 = field.getAnnotation(Value.class);
                if (value1 != null) {
                    String str = value1.value();
                    //判断是否存在${,并且不存在#{
                    if (str.contains("${")) {
                        //截取${}中的内容
                        str = str.substring(str.indexOf("${") + 2, str.indexOf("}"));
                        //判断是否和key相等
                        if (str.equals(key)) {
                            list.add(value);
                        }
                    }
                }
            }
        }
        return list;
    }


    //获取bean的所有@Value成员方法
    public List<String> getFieldValues(Object bean) {
        Class target = SpringAopProxyUtil.getTargetClass(bean);
        List<String> list = new ArrayList<>();
        Field[] fields = target.getDeclaredFields();
        for (Field field : fields) {
            Value value = field.getAnnotation(Value.class);
            if (value != null) {
                list.add(field.getName());
            }
        }
        return list;
    }

    //刷新bean的成员变量
    public void refreshField( Object bean, List<String> fields, String key, String value) {
        Object target = SpringAopProxyUtil.getTarget(bean);
        Class targetClass = SpringAopProxyUtil.getTargetClass(bean);
        ApplicationContext applicationContext = SpringContextUtil.getApplicationContext();
        for (String field : fields) {
            try {
                Field declaredField = targetClass.getDeclaredField(field);
                //获取属性上的@Value注解
                Value value1 = declaredField.getAnnotation(Value.class);
                //解析spEl表达式
                String newValue = SpELUtil.spElParser(value1.value(), String.class, applicationContext);
                declaredField.setAccessible(true);
                declaredField.set(target, newValue);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
